using System;
using System.Collections.Generic;
#if(!WindowsCE)
using System.Linq.Expressions;
#endif
using System.Reflection;
using ValidationFramework.Extensions;
using System.Linq;

namespace ValidationFramework
{
    /// <summary>
    /// The validation policy for a given type
    /// </summary>
#if (!SILVERLIGHT)
    [Serializable]
#endif
    public class TypePolicy
    {
		IValidationPolicyFactory _vpFactory;
        // --- Constructors

		internal TypePolicy()
		{
			_vpFactory = new ValidationPolicyFactory();
		}

        /// <summary>
        /// Initialize a new instance of the <see cref="TypeDescriptor"/> class.
        /// </summary>
		/// <param name="typeToCreateDescriptorFor">The <see cref="System.Type"/> for the <see cref="Type"/> to wrap.</param>
        /// <exception cref="ArgumentException"><paramref name="runtimeTypeHandle"/> represents an interface.</exception>
        internal TypePolicy(IValidationPolicyFactory vpFactory)
        {
			_vpFactory = vpFactory;

			PropertyPolicyDictionary = new Dictionary<PropertyKey, IValidationPolicy>();
			FieldPolicyDictionary = new Dictionary<FieldKey, IValidationPolicy>();

			ReadOnly = true;
        }

        // --- Properties

        public Dictionary<PropertyKey, IValidationPolicy> PropertyPolicyDictionary
        {
            get;
            private set;
        }

		public Dictionary<FieldKey, IValidationPolicy> FieldPolicyDictionary
        {
            get;
            private set;
        }

		public int RuleCount
		{
			get
			{
				return PropertyPolicyDictionary.Sum(x => x.Value.RuleCount);
			}
		}

		// --- Methods | Validation Policys
		private void GetPropertyPolicies()
		{
			
		}

		public bool ReadOnly
		{
			get;
			set;
		}

		/// <summary>
		/// Adds a rule to the validation policy at the given property key
		/// </summary>
		/// <param name="key"></param>
		/// <param name="rule"></param>
		/// <param name="scope"></param>
		/// <remarks>If a descriptor with the given key doesn't exist one will be created</remarks>
		public IValidationPolicy GetOrCreatePropertyPolicy(PropertyKey key)
		{
			IValidationPolicy policy;
			if (!PropertyPolicyDictionary.TryGetValue(key, out policy))
			{
				// create and add one
				var newPolicy = _vpFactory.CreatePropertyValidationPolicy(key);
				PropertyPolicyDictionary.Add(key, newPolicy);
				return newPolicy;
			}
			else
				return policy;
		}

		public void RemoveProperty(PropertyKey key)
		{
			PropertyPolicyDictionary.Remove(key);
		}

		/// <summary>
		/// Adds a rule to the given field's validation policy
		/// </summary>
		/// <param name="key"></param>
		/// <param name="rule"></param>
		/// <param name="scope"></param>
		public IValidationPolicy GetOrCreateFieldPolicy(FieldKey key)
		{
			IValidationPolicy policy;
			if (!FieldPolicyDictionary.TryGetValue(key, out policy))
			{
				// create and add one
				var newPolicy = _vpFactory.CreateFieldValidationPolicy(key);
				FieldPolicyDictionary.Add(key, newPolicy);
				return newPolicy;
			}
			else
				return policy;
		}

		public void RemoveField(FieldKey key)
		{
			FieldPolicyDictionary.Remove(key);
		}


		public IList<ValidationError> Validate(object instance, ValidationOptions options)
		{
			// validate each policy saving errors to the errorlist
			var errors = new List<ValidationError>();

			foreach (var kvp in PropertyPolicyDictionary)
			{
				var policy = kvp.Value;

				errors.AddRange(policy.Validate(instance, options));
			}

			foreach (var kvp in FieldPolicyDictionary)
			{
				var policy = kvp.Value;

				errors.AddRange(policy.Validate(instance, options));
			}

			return errors;
		}
    }
}